package com.config;

import com.controller.vo.OrderItem;
import com.controller.vo.PaymentInfo;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Retryer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignCircuitBreaker;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;

@Configuration
@EnableFeignClients
public class FeignForAppsConfig {
    @Autowired
    SSLContext sslContext;


    @Bean
    public Client feignForAppsClient(LoadBalancerClient loadBalancerClient,
                                        LoadBalancerClientFactory loadBalancerClientFactory) throws Exception {

        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        };
        Client.Default aDefault = new Client.Default(socketFactory, hostnameVerifier);

        return new FeignBlockingLoadBalancerClient(aDefault, loadBalancerClient, loadBalancerClientFactory);
    }

    @Configuration(proxyBeanMethods = false)
    public static class CustomConfiguration extends FeignClientsConfiguration {
        @Primary
        @Configuration(proxyBeanMethods = false)
        @Conditional(FeignCircuitBreakerDisabledConditions.class)
        protected static class DefaultFeignBuilderConfiguration {
            @Autowired
            Client feignForAppsClient;
            @Autowired
            Contract feignContract;

            @Primary
            @Bean
            @Scope("prototype")
            @ConditionalOnMissingBean
            public Feign.Builder feignBuilder(Retryer retryer) {
                return Feign.builder().retryer(retryer).contract(feignContract).client(feignForAppsClient);
            }

        }
        @Primary
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass(CircuitBreaker.class)
        @ConditionalOnProperty("feign.circuitbreaker.enabled")
        protected static class CircuitBreakerPresentFeignBuilderConfiguration {
            @Autowired
            Client feignForAppsClient;
            @Autowired
            Contract feignContract;

            @Primary
            @Bean
            @Scope("prototype")
            @ConditionalOnMissingBean({ Feign.Builder.class, CircuitBreakerFactory.class })
            public Feign.Builder defaultFeignBuilder(Retryer retryer) {
                return Feign.builder().client(feignForAppsClient).contract(feignContract).retryer(retryer);
            }
            @Primary
            @Bean
            @Scope("prototype")
            @ConditionalOnMissingBean
            @ConditionalOnBean(CircuitBreakerFactory.class)
            public Feign.Builder circuitBreakerFeignBuilder() {
                return FeignCircuitBreaker.builder().contract(feignContract).client(feignForAppsClient);
            }

        }
    }
    /**
     use loadbalance .
     */
    @org.springframework.cloud.openfeign.FeignClient( name = "https://orderservice", contextId = "feignClientforHttp",configuration = {CustomConfiguration.class})
    public interface FeignClientForOrder {
        @PostMapping(value = "order")
        public String order(@RequestHeader("Authorization") String headers,  OrderItem shirt);
    }
    @org.springframework.cloud.openfeign.FeignClient( name = "https://paymentservice", contextId = "feignClientforPayment",configuration = {CustomConfiguration.class})
    public interface FeignClientForPayment {
        @PostMapping(value = "payment")
        public String payment(@RequestHeader("Authorization") String headers,  PaymentInfo paymentInfo);
    }

}
